package eval;

import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import network.Device;
import network.Network;
import network.Rule;
import networkLoader.FBNetwork;

import java.util.*;
import java.util.concurrent.*;

public class EventEmiter implements Runnable {
    private BlockingQueue<Rule> blockingQueue;
    private List<List<Rule>> rulesList;
    private List<List<Rule>> rulesInterval;
    private Iterator<List<Rule>> intervalIte;
    private Iterator<List<Rule>> iterator;
    private ScheduledFuture<?> scheduledFuture;
    private HashMap<List<Rule>, Long> rulesToInterval = new HashMap<>();

    public EventEmiter(BlockingQueue<Rule> blockingQueue) {
        this.blockingQueue = blockingQueue;
    }

    public EventEmiter(Network network, BlockingQueue<Rule> blockingQueue, int nRulesPerSec) {
        this.blockingQueue = blockingQueue;
//        for (Rule rule : network.getInitialRules()) {
//            if (Math.random() < (double) 1 / 1000) {
//                rule.setRandomOutPort();
//            }
//        }

        for (Device device : network.getAllDevices()) {
            device.getInitialRules().get(device.getInitialRules().size() - 1).setLast(true);
        }

        this.rulesList = Lists.partition(network.getInitialRules(), nRulesPerSec);
        for (Device device: network.getAllDevices()) {
            this.rulesInterval.add(device.getInitialRules());
        }
        this.intervalIte = rulesInterval.iterator();
//        System.out.println("#rules total: " + network.getInitialRules().size());
//        System.out.println("#batchs: " + rulesList.size());
        this.iterator = rulesList.iterator();
    }

    public void addRulesToInterval(List<Rule> rules, long interval) {
        this.rulesToInterval.put(rules, interval);
    }

    public static long startAt;
//    public void run() {
//        Runnable dispatcher = () -> {
//            if (iterator.hasNext()) {
////                System.out.println("new emit");
//                blockingQueue.addAll(iterator.next());
////                System.out.println(blockingQueue.size());
//            } else {
//                scheduledFuture.cancel(true);
//            }
//        };
//        ScheduledExecutorService executor = Executors.newScheduledThreadPool(0);
//        scheduledFuture = executor.scheduleAtFixedRate(dispatcher, 0, 1, TimeUnit.SECONDS);
//        startAt = System.nanoTime();
//        System.out.println("started at: " + startAt);
//    }

    public void run() {
        startAt = System.nanoTime();
        System.out.println("started at: " + startAt);
        System.out.println(this.rulesToInterval.size());
        for (Map.Entry<List<Rule>, Long> entry : this.rulesToInterval.entrySet()) {
            TimerTask task = new TimerTask() {
                @Override
                public void run() {
                    blockingQueue.addAll(entry.getKey());
                    System.out.println("emitted");
                    this.cancel();
                }
            };
            Timer timer = new Timer("timer");
            timer.schedule(task, entry.getValue());
        }
        System.out.println("schedule end");
    }
}
